package com.k2data.k2app.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.k2data.k2app.common.MyConstant;
import com.k2data.k2app.domain.po.EarlyWaringDO;
import com.k2data.k2app.domain.po.ModelDO;
import com.k2data.k2app.domain.po.TaskDTO;
import com.k2data.k2app.domain.vo.*;
import com.k2data.k2app.mapper.EarlyWaringMapper;
import com.k2data.k2app.mapper.ModelMapper;
import com.k2data.k2app.mapper.TaskMapper;
import com.k2data.k2app.service.pas04.Pas04ResultService;
import com.k2data.k2app.service.pas14.Model14Service;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 预警处理
 * Created by clb on 17-4-18.
 */
@Log4j2
@Service
public class ModelService{

    @Autowired
    private ModelMapper modelMapper;
    @Autowired
    private Pas04ResultService pas04ResultService;
    @Autowired
    private Model14Service modelService;
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private TaskService deviceTaskService;
    @Autowired
    private EarlyWaringMapper earlyWaringMapper;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private JobTaskService jobTaskService;
    @Autowired
    private JobService jobService;
    @Autowired
    private MyConstant myConstant;

    public List getResult(boolean isTemplate,Long id,Integer pageNum,Integer pageSize) throws Exception{
        List list = new ArrayList();
        if(isTemplate){
            //获取所有复制模型
            TaskDTO taskDO = new TaskDTO();
            taskDO.setModelId(id);
            List<TaskDTO> tasks = taskMapper.queryList(taskDO);
            for(TaskDTO taskDO1 :tasks){
                if(taskDO1.getModelIdCopy() == null){
                    continue;
                }
                Long modelId = taskDO1.getModelIdCopy();
                List<Job> jobs =  jobService.listJobs(null,modelId,1,30,null);
                if(jobs.size() == 0){
                    continue;
                }
                for(Job job:jobs){
                    if("false".equals(job.getHasApi())){
                        continue;
                    }
                    List results = pas04ResultService.getInterfaces(modelId,null,null,null,null);
                    list.addAll(results);
                }
            }
        }else{
            list = pas04ResultService.getInterfaces(id,null,null,pageNum,pageSize);
        }
        return list;
    }

    /**
     * 统计信息
     * @return
     */
    public ModelCount getCount(Long modelId,Long userId) throws Exception{
        ModelCount modelCount = new ModelCount();
        modelCount.setModelId(modelId);
        //1 获取任务个数
        TaskDTO taskDO = new TaskDTO();
        taskDO.setModelId(modelId);
        List<TaskDTO> tasks = deviceTaskService.listWithDevice(taskDO,true);
        modelCount.setTaskCount(tasks.size());
        //2 作业个数
        int jobs = 0;
        for(TaskDTO taskDO1 :tasks){
            if(taskDO1.getModel()!=null){
                if(taskDO1.getModel().getJobCount()!=null){
                    jobs += taskDO1.getModel().getJobCount();
                }
            }
        }
        modelCount.setJobCount(jobs);
        //设备
        List devices = listDevices(modelId);
        modelCount.setDeviceCount(devices.size());
        //客户
        List customers = listCustomers(modelId,userId);
        modelCount.setCustomerCount(customers.size());
        //预警
        List<EarlyWaringDO> earlyWaringDOs = earlyWaringMapper.getByModelId(modelId);
        //忽略的,生成工单,站内预警,短信处理的,邮件处理的,不做处理的
        int ignore = 0,order = 0,amp = 0,sms = 0,mail = 0,noDeal = 0;
        for(EarlyWaringDO earlyWaringDO : earlyWaringDOs){
            if(earlyWaringDO.getIsMail()==null && earlyWaringDO.getIsMq()== null && earlyWaringDO.getIsSms() == null){
                noDeal++;
            }else{
                if(earlyWaringDO.getIsMq() != null){
                    if(earlyWaringDO.getIsMq()==1){
                        amp++;
                    }else if(earlyWaringDO.getIsMq()==2){
                        ignore++;
                    }else if(earlyWaringDO.getIsMq()==3){
                        order++;
                    }
                }
                if(earlyWaringDO.getIsSms() != null){
                    if(earlyWaringDO.getIsSms()==1){
                        sms++;
                    }
                }
                if(earlyWaringDO.getIsMail() != null){
                    if(earlyWaringDO.getIsMail()==1){
                        mail++;
                    }
                }
            }
        }
        ModelCount.WarningCount warningCount
                = modelCount.new WarningCount(earlyWaringDOs.size(),ignore,order,amp,sms,mail,noDeal);
        modelCount.setWarningCount(warningCount);
        return modelCount;
    }

    /**
     * 获取模型对应的设备
     * @param modelId
     * @return－
     * @throws Exception
     */
    public List listDevices(Long modelId) throws Exception{
        List<Map> list = new ArrayList<>();
        TaskDTO taskDO = new TaskDTO();
        taskDO.setModelId(modelId);
        List<TaskDTO> tasks = taskMapper.queryList(taskDO);

        for (TaskDTO healthTask : tasks) {
            if (healthTask.getCustomerId() == null) {
                return deviceService.getDevices();
            }
        }

        List deviceIds = taskMapper.deviceIds(taskDO);
        if(deviceIds != null && deviceIds.size()>0){
            deviceIds.forEach(deviceId -> {
                try {
                    Map map =  deviceService.getDeviceById(Long.parseLong(deviceId.toString()));
                    list.add(map);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }else{
            return deviceService.getDevices();
        }
        return list;
    }

    public List<Job> listJobs(Long modelId) throws Exception {
        //1 获取所有任务
        TaskDTO taskDO = new TaskDTO();
        taskDO.setModelId(modelId);
        List<TaskDTO> tasks = taskService.queryList(taskDO);
        List<Job> jobs = new ArrayList<>();
        if(tasks != null){
            //2 根据model_copy_id获取所有作业
            for(TaskDTO taskDO1 :tasks){
                List<Job> jobs1 = jobService.listJobs(null, taskDO1.getModelIdCopy(),null,null,null);
                jobs.addAll(jobs1);
            }
        }
        return jobs;
    }

    public List<TaskDTO> listTasks(Long modelId) throws Exception {
        TaskDTO taskDTO = new TaskDTO();
        taskDTO.setModelId(modelId);
        List<TaskDTO> list = taskService.listWithDevice(taskDTO,false);
        for(TaskDTO taskDTO1:list){
            taskService.setCustomInfo(taskDTO1);
        }
        return list;
    }

    public List listCustomers(Long modelId,Long userId) throws Exception{
        TaskDTO taskDO = new TaskDTO();
        taskDO.setModelId(modelId);
        List<Map> customers = new ArrayList<>();
        List<TaskDTO> list = taskMapper.queryList(taskDO);
        List<Long> customerIds = new ArrayList<>();
        for (TaskDTO healthTask : list) {
            if (healthTask.getCustomerId() == null) {
                List customersAll = deviceService.getCustomers();
                return customersAll;
            }
            if (!customerIds.contains(healthTask.getCustomerId())) {
                Map customer = deviceService.getCustomerById(healthTask.getCustomerId());
                customers.add(customer);
                customerIds.add(healthTask.getCustomerId());
            }
        }
        return customers;
    }

    /**
     * 根据 [设备] 查询模型
     */
    public List<Model> listModelsByDevice(Long deviceId)  throws Exception{
        List<Model> list = new ArrayList();
        List<Long> modelIds = new ArrayList<>();
        TaskDTO taskDO = new TaskDTO();
        taskDO.setDeviceId(deviceId);
        List<TaskDTO> tasks = taskMapper.listWithDevices(taskDO);
        for(int i = 0;i<tasks.size();i++){
            TaskDTO task = tasks.get(i);
            if(task.getModelId()!=null && !modelIds.contains(task.getModelId())){
                modelIds.add(task.getModelId());
                Optional<Model> model = Optional.ofNullable(get(task.getModelId(),false));
                model.ifPresent(m -> list.add(m));
            }
        }
        return list;
    }

    /**
     * 模型分组
     * 按照模型类型分组
     */

    public List<ModelType> listGroupByType(List<Model> models)  throws Exception{
        List<ModelType> modelTypes = new ArrayList<>();
        List<String> modelTypesNames = new ArrayList<>();
        Map<String ,List<Model>> map = new HashMap<>(16);
        for(int i = 0;i<models.size();i++){
            Model model = models.get(i);
            //分组
            if(!modelTypesNames.contains(model.getAnalysisType())){
                modelTypesNames.add(model.getAnalysisType());
            }
            List<Model> list = map.get(model.getAnalysisType());
            if(list == null){
                list = new ArrayList<>();
            }
            list.add(model);
            map.put(model.getAnalysisType(),list);
        }
        Collections.sort(modelTypesNames);
        modelTypesNames.stream().forEach(item -> {
            ModelType modelType = new ModelType();
            modelType.setName(item);
            modelType.setAlgs(map.get(item));
            modelTypes.add(modelType);
        });
        return modelTypes;
    }

    /**
     * 根据id查询
     * @param modelId
     * @param withTask 是否绑定任务
     * @return
     * @throws Exception
     */
    public Model get(Long modelId, boolean withTask)  throws Exception{
        Optional<Model> model = Optional.ofNullable(modelService.get(modelId));
        model.ifPresent(m->{
            // 是否可用
            boolean useful = isUseful(m.getId());
            m.setUseFul(useful);
            //是否绑定任务
            if(withTask){
                m = getModelWithTask(m);
            }
        });
        return model.orElse(null);
    }

    /**
     * 删除模型
     * 删除模型可用性记录，删除pas上模型和作业
     * @param modelId 模型id
     * @return
     */
    @Transactional
    public Long delete(Long modelId) {
        log.debug("删除模型相关信息!");
        //1 删除模型可用信息
        modelMapper.deleteByModelId(modelId);
        log.debug("模型"+modelId+"有效性记录删除");
        //2 删除作业记录
        jobTaskService.deleteByProjectId(modelId);
        log.debug("模型"+modelId+"和作业的关联关系解除");
        //2 删除pas模型作业
        List<Job> jobs = null;
        try {
            jobs = jobService.listAllJobs(null, modelId,null,null,null);
            for(Job job:jobs){
                jobService.deletePasJob(modelId,job.getJobId());
            }
            //3 删除pas模型
            modelService.delete(modelId);
        } catch (Exception e) {
            log.error(String.format("模型作业或者模型作业删除出错![pas return message:%s]",e.getMessage()));
        }
        return modelId;

    }

    /**
     * <p>简单模型</p>
     * <p>只有模型id 和 name 值</p>
     * @return
     * @throws Exception
     */
    public List listSimple() throws Exception{
        List<Model> models = list(true);
        models = fiterUserful(models);
        List<ModelSimple> modelSimples = new ArrayList<>();
        for(int i =0;i<models.size();i++){
            ModelSimple modelSimple = new ModelSimple();
            modelSimple.setId(models.get(i).getId());
            modelSimple.setProjName(models.get(i).getName());
            modelSimples.add(modelSimple);
        }
        return modelSimples;
    }

    /**
     * 模型
     * @param noGroup 是否分组
     * @return
     * @throws Exception
     */
    public List list(boolean noGroup) throws Exception {
        List<Model> modelsWithTask = new ArrayList<>();
        List<Model> models = modelService.list();
        // 模型绑定任务
        for(Model model:models){
            Model modelWithTask = getModelWithTask(model);
            boolean useful = isUseful(model.getId());
            modelWithTask.setUseFul(useful);
            modelsWithTask.add(modelWithTask);
        }
        if(noGroup){
            return modelsWithTask;
        }else{
            return listGroupByType(modelsWithTask);
        }
    }

    /**
     * 模型绑定任务
     */
    public Model getModelWithTask(Model model){
        //绑定任务
        TaskDTO taskDO = new TaskDTO();
        taskDO.setModelId(model.getId());
        List<TaskDTO> list = taskMapper.listWithDevices(taskDO);
        for(TaskDTO taskDTO:list){
            taskService.setDevicePart(taskDTO);
            taskService.setCustomInfo(taskDTO);
        }
        model.setTasks(list);
        return model;
    }



    /**
     * 过滤可用模型
     * @param models 模型列表
     * @return
     */
    public List<Model> fiterUserful(List<Model> models){
        List<Model> list = new ArrayList<>();
        for(Model model:models){
            if(model.isUseFul()){
                list.add(model);
            }
        }
        return list;
    }

    /**
     * <p>模型是否有效</p>
     * 当界面对模型有效性修改后，数据库会存在模型的有效性记录，如果库中没有记录，则模型没做过有效性修改，视为有效
     *
     * @param modelId 模型id
     * @return
     */
    public Boolean isUseful(Long modelId){
        Boolean flag = false;
        ModelDO modelDO = modelMapper.getByModelId(modelId);
        if(modelDO == null){
            flag = false;
        }else{
            flag = modelDO.getUseful() == MyConstant.USEFUL?true:false;
        }
        return flag;
    }

    /**
     * <p>更新模型有效性属性</p>
     *
     * <p>如果库中存在模型有效性记录信息，则修改，否则添加记录</p>
     * 如果是模板模型，则对应的复制模型，均做修改
     *
     * @param modelId 模型id
     * @param useful 是否有效
     * @param isTemplate 是否模板模型
     * @return
     */
    public Integer updateUseFul(Long modelId, boolean useful, Boolean isTemplate){
        ModelDO modelDO = new ModelDO();
        modelDO.setModelId(modelId);
        if(useful){
            modelDO.setUseful(MyConstant.USEFUL);
        }else{
            modelDO.setUseful(MyConstant.UNUSEFUL);
            if(isTemplate != null && isTemplate){
                modelMapper.updateUsefulByTemplate(modelDO);
            }
        }
        ModelDO modelDo1 = modelMapper.getByModelId(modelId);
        if(modelDo1 == null) {
            modelMapper.insertRecord(modelDO);
        }else{
            modelMapper.updateByPrimaryKeySelective(modelDO);
        }
        return 0;
    }

    @Transactional
    public Integer insertRecord(ModelDO modelDO){
        return modelMapper.insertRecord(modelDO);
    }



    public Long copyAndEdit(TaskDTO taskDTO) throws Exception {
        //2 设备和通道，测点变量
        setFieldGroup(taskDTO);
        setVarData(taskDTO);
        setCustomer(taskDTO);
        return modelService.copyAndEdit(taskDTO);
    }

    public Long editProject(TaskDTO taskDTO) throws Exception {
        setFieldGroup(taskDTO);
        setVarData(taskDTO);
        setCustomer(taskDTO);
        return modelService.edit(taskDTO);
    }

    public Long run(Long projectId,String start,String end) throws Exception {
        modelService.editDataSetTime(projectId,start,end);
        return modelService.run(projectId);
    }


    /**
     * 将任务的测点变量转换为key,label,value格式
     *
     * <p>key:{@code 测点变量id}
     * <p>label:{@code kmxVariableName}
     * <p>value:{@code variableType}和{@codekmxVariableNameEn}用逗号相连
     * @param taskDTO
     * @throws Exception
     */
    public void setVarData(TaskDTO taskDTO) throws Exception{
        // 所有的设备
        List<String> machineIds = Lists.newArrayList();
        // 所有的通道
        List<String> channelIds = Lists.newArrayList();
        List<String> kmxVariableNameEns = Lists.newArrayList();
        // 设置测点变量值
        List<LabelValueKeyObject> variables = new ArrayList<>();
        List<LabelValueKeyObject> varData = taskDTO.getVarData();
        for(LabelValueKeyObject stmtSelect:varData){

            String[] ids = stmtSelect.getKey().split("_");
            if(!ids[0].equals("all")){
                Map device = deviceService.getDeviceById(Long.parseLong(ids[0]));
                if(device != null && device.get("deviceNo") != null){
                    String deviceNo = device.get("deviceNo").toString();
                    if(!machineIds.contains(deviceNo.split("_")[2])){
                        machineIds.add(deviceNo.split("_")[2]);
                    }
                }
            }


            if(!ids[2].equals("all") && !channelIds.contains(ids[2])){
                channelIds.add(ids[2]);
            }

            taskDTO.setDeviceIds(machineIds);
            taskDTO.setChannelIds(channelIds);
            Map map1 = deviceService.getTemplateVariablesById(Long.parseLong(ids[3]));
            if(map1.size() == 0) {
                continue;
            }
            if(!kmxVariableNameEns.contains(map1.get("kmxVariableNameEn").toString())){
                LabelValueKeyObject labelValueKeyObject = new LabelValueKeyObject();
                labelValueKeyObject.setKey(map1.get("id").toString());
                labelValueKeyObject.setLabel(map1.get("kmxVariableName").toString());
                labelValueKeyObject.setValue(map1.get("variableType").toString()+","+map1.get("kmxVariableNameEn").toString());
                variables.add(labelValueKeyObject);
                //重复的变量名称不重复添加
                kmxVariableNameEns.add(map1.get("kmxVariableNameEn").toString());
            }

        }
        taskDTO.setVarData(variables);
    }

    /**
     * 将任务的测点变量转换为key,label,value格式
     *
     * <p>key:{@code 测点变量id}
     * <p>label:{@code kmxVariableName}
     * <p>value:{@code variableType}和{@codekmxVariableNameEn}用逗号相连
     * @param taskDTO
     * @throws Exception
     */
    public void setVarDataOld(TaskDTO taskDTO) throws Exception{
        List<LabelValueKeyObject> varData = taskDTO.getVarData();
        // 所有的设备
        List<String> machineIds = Lists.newArrayList();
        // 所有的通道
        List<String> channelIds = Lists.newArrayList();
        List<String> kmxVariableNameEns = Lists.newArrayList();
        // 设置测点变量值
        List<LabelValueKeyObject> variables = new ArrayList<>();
        for(LabelValueKeyObject stmtSelect:varData){

            String[] ids = stmtSelect.getKey().split("_");
            Map device = deviceService.getDeviceById(Long.parseLong(ids[0]));
            if(device != null && device.get("deviceNo") != null){
                String deviceNo = device.get("deviceNo").toString();
                if(!machineIds.contains(deviceNo.split("_")[2])){
                    machineIds.add(deviceNo.split("_")[2]);
                }
            }

            if(!channelIds.contains(ids[2])){
                channelIds.add(ids[2]);
            }
            taskDTO.setDeviceIds(machineIds);
            taskDTO.setChannelIds(channelIds);
            Map map1 = deviceService.getDeviceVariablesById(Long.parseLong(ids[3]));
            if(map1.size() == 0) {
                continue;
            }
            if(!kmxVariableNameEns.contains(map1.get("kmxVariableNameEn").toString())){
                LabelValueKeyObject labelValueKeyObject = new LabelValueKeyObject();
                labelValueKeyObject.setKey(map1.get("id").toString());
                labelValueKeyObject.setLabel(map1.get("kmxVariableName").toString());
                labelValueKeyObject.setValue(map1.get("variableType").toString()+","+map1.get("kmxVariableNameEn").toString());
                variables.add(labelValueKeyObject);
                //重复的变量名称不重复添加
                kmxVariableNameEns.add(map1.get("kmxVariableNameEn").toString());
            }

        }
        taskDTO.setVarData(variables);
    }

    /**
     * 设置任务新建模型的fieldGroup
     * @param taskDTO
     * @throws Exception
     */
    public void setFieldGroup(TaskDTO taskDTO) throws Exception{
        // 获取模型需要的信息
        // 1 表名称
        String groupId = "";
        if(taskDTO.getVarData().size()>0){
            String monitorPointId = taskDTO.getVarData().get(0).getKey().split("_")[1];
            Map devicePoint = Maps.newHashMap();
            devicePoint = deviceService.getTempplatePoint(Long.parseLong(monitorPointId));
            if(devicePoint!=null){
                groupId = myConstant.getFieldGroup(devicePoint.get("nameEn").toString());
            }
        }
        taskDTO.setFieldGroupId(groupId);
    }
    /**
     * 设置任务新建模型的fieldGroup
     * @param taskDTO
     * @throws Exception
     */
    public void setCustomer(TaskDTO taskDTO) throws Exception{
        if(taskDTO.getCustomerId()!=null){
            Map customer = deviceService.getCustomerById(taskDTO.getCustomerId());
            LabelValueKeyObject taskCustomre = new LabelValueKeyObject();
            taskCustomre.setKey(customer.get("id").toString());
            taskCustomre.setValue(customer.get("customerNo").toString());
            taskCustomre.setLabel(customer.get("name").toString());
            taskDTO.setCustomer(taskCustomre);
        }
    }
}
